package com.solocredit.finance.http

import android.os.Handler
import android.os.Looper
import com.google.gson.Gson
import com.solocredit.finance.base.utils.log.JsonFormat
import com.solocredit.finance.base.utils.log.MullaLog
import com.solocredit.finance.config.MullaConfigs
import com.solocredit.finance.http.ApiService.addCommonParams
import com.solocredit.finance.http.ApiService.addRandomParams
import com.solocredit.finance.utils.okhttp.callback.StringCallback
import com.solocredit.finance.utils.okhttp.model.HttpParams
import org.json.JSONObject
import java.io.BufferedReader
import java.io.DataOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLConnection
import java.util.UUID
import javax.net.ssl.HttpsURLConnection

/**
 * MullaFlow
 * @Author wwdeng
 * @CreateTime: 2025/3/24 17:55
 * @Annotation：
 */
class HttpConnectLoader: IHttpLoader {

    private final val mainHandler = Handler(Looper.getMainLooper())
    override fun getMullaAction(url: String, params: HttpParams, callback: IHttpCallback) {
        MullaLog.e("HttpUrl：  $url")
        MullaLog.e("HttpParams： $params")
        val body = Gson().toJson(params).trim { it <= ' ' }
        load("GET", url, JSONObject(body), onSuccess = { result ->
            if (result.isNotBlank()) {
                Thread {
                    MullaLog.i("url：$url --> " + JsonFormat.format(result))
                }.start()
                val data = JSONObject(result)
                callback.onRequestSuccess(data)
            } else {
                val errorObj = JSONObject()
                errorObj.put("errorCode", -1)
                errorObj.put("errorMsg", "http request error")
                callback.onRequestError(errorObj)
            }
        },
            onFailure = { code, msg ->
                val errorObj = JSONObject()
                errorObj.put("errorCode", code)
                errorObj.put("errorMsg", msg)
                callback.onRequestError(errorObj)
            },
            onFinished = {
                callback.onRequestFinish()
            }
        )
    }

    override fun postMullaAction(url: String, params: JSONObject, callback: IHttpCallback) {
        MullaLog.e("HttpUrl：  $url")
        MullaLog.e("HttpParams： $params")
        load("POST",url, params, onSuccess = { result ->
            if (result.isNotBlank()) {
                Thread {
                    MullaLog.i("url：$url --> " + JsonFormat.format(result))
                }.start()
                val data = JSONObject(result)
                callback.onRequestSuccess(data)
            } else {
                val errorObj = JSONObject()
                errorObj.put("errorCode", -1)
                errorObj.put("errorMsg", "http request error")
                callback.onRequestError(errorObj)
            }
        },
            onFailure = { code, msg ->
                val errorObj = JSONObject()
                errorObj.put("errorCode", code)
                errorObj.put("errorMsg", msg)
                callback.onRequestError(errorObj)
            },
            onFinished = {
                callback.onRequestFinish()
            }
        )
    }

    override fun postMullaEventAction(url: String, params: JSONObject, callback: IHttpCallback) {

    }

    override fun addMullaEventAction(eventName: String, remark: String) {
        val eventType = eventName.uppercase()//转大写
        val httpUrl = ApiService.getHttpUrl(ApiService.API_PATH.MULLA_API_TRACK_EVENT_PATH)
        val params = JSONObject().addCommonParams().addRandomParams().apply {
//            put("path", ApiService.API_PATH.MULLA_API_TRACK_EVENT_PATH)
            put("type",eventType)//事件类型
            put("remark",remark)//事件备注
        }
        MullaLog.e("event url：  $httpUrl")
        MullaLog.e("event params： $params")
        load("POST",httpUrl, params,
            onSuccess = { result ->

            },
            onFailure = { code, msg ->
            },
            onFinished = {
            }
        )
    }

    override fun uploadMullaFileAction(httpUrl: String, filePath: String, callback: StringCallback) {

    }

    override fun uploadMullaFileAction(httpUrl: String, filePath: String, callback: IHttpCallback) {
        Thread{
            uploadFile(httpUrl,filePath,onSuccess = { result ->
                if (result.isNotBlank()) {
                    Thread {
                        MullaLog.i("url：$httpUrl --> " + JsonFormat.format(result))
                    }.start()
                    val data = JSONObject(result)
                    callback.onRequestSuccess(data)
                } else {
                    val errorObj = JSONObject()
                    errorObj.put("errorCode", -1)
                    errorObj.put("errorMsg", "http request error")
                    callback.onRequestError(errorObj)
                }
            },
                onFailure = { code, msg ->
                    val errorObj = JSONObject()
                    errorObj.put("errorCode", code)
                    errorObj.put("errorMsg", msg)
                    callback.onRequestError(errorObj)
                },
                onFinished = {
                    callback.onRequestFinish()
                }
            )
        }.start()
    }

    private fun load(method: String, url: String, params: JSONObject, onSuccess: (String) -> Unit, onFailure: (Int, String) -> Unit,onFinished: () -> Unit) {
        Thread{
            try {
                val httpConnection = httpsURLConnection(url,method)
                httpConnection.outputStream.write(params.toString().toByteArray())
                httpConnection.outputStream.flush()
                httpConnection.outputStream.close()
                try {
                    val resCode = httpConnection.responseCode
                    if (resCode == HttpURLConnection.HTTP_OK) {
                        val result = StringBuilder()
                        BufferedReader(InputStreamReader(httpConnection.inputStream)).use { reader ->
                            var line: String?
                            while (reader.readLine().also { line = it } != null) {
                                result.append(line)
                            }
                            reader.close()
                            mainHandler.post {
                                onSuccess.invoke(result.toString())
                            }
                        }
                    } else {
                        mainHandler.post {
                            onFailure.invoke(resCode, httpConnection.responseMessage)
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    mainHandler.post {
                        onFailure.invoke(-1, e.localizedMessage ?: "")
                    }
                } finally {
                    httpConnection.inputStream.close()
                    httpConnection.disconnect()
                    mainHandler.post {
                        onFinished()
                    }
                }
            } catch (e: IOException) {
                mainHandler.post {
                    onFailure.invoke(-1, e.localizedMessage ?: "")
                    onFinished()
                }
            }
        }.start()
    }

    private fun uploadFile(url: String, filePath: String, onSuccess: (String) -> Unit, onFailure: (Int, String) -> Unit, onFinished: () -> Unit) {
        val boundary = UUID.randomUUID().toString()
        val twoHyphens = "--"
        val lineEnd = "\r\n"
        val file = File(filePath)

        if (!file.exists()) {
            mainHandler.post {
                onFailure.invoke(-1, "File not found: $filePath")
            }
            return
        }

        try {
            val urlConnection = httpsURLConnection(url,"POST")
            urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")
            val contentType = URLConnection.guessContentTypeFromName(file.name) ?: "application/octet-stream"
            val outputStream = DataOutputStream(urlConnection.outputStream)

            // 写入 multipart 表单头部
            outputStream.writeBytes("$twoHyphens$boundary$lineEnd")
            outputStream.writeBytes("Content-Disposition: form-data; name=\"image\"; filename=\"${file.name}\"$lineEnd")
            outputStream.writeBytes("Content-Type: $contentType$lineEnd")
            outputStream.writeBytes(lineEnd)

            // 读取文件数据
            val fileInputStream = FileInputStream(file)
            val buffer = ByteArray(4096)
            var bytesRead: Int
            while (fileInputStream.read(buffer).also { bytesRead = it } != -1) {
                outputStream.write(buffer, 0, bytesRead)
            }
            fileInputStream.close()

            outputStream.writeBytes(lineEnd)
            outputStream.writeBytes("$twoHyphens$boundary$twoHyphens$lineEnd")
            outputStream.flush()
            outputStream.close()

            try {
                val responseCode = urlConnection.responseCode
                val responseMessage = urlConnection.responseMessage
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    val reader = BufferedReader(InputStreamReader(urlConnection.inputStream))
                    val result = StringBuilder()
                    var line: String?
                    while ((reader.readLine().also { line = it }) != null) {
                        result.append(line)
                    }
                    reader.close()
                    MullaLog.i("file url>>>>>>>>>>>>>>>>$result")
                    mainHandler.post {
                        onSuccess.invoke(result.toString())
                    }
                } else {
                    mainHandler.post {
                        onFailure.invoke(responseCode, responseMessage)
                    }

                }
            } catch (e: Exception) {
                mainHandler.post {
                    onFailure.invoke(-1, e.localizedMessage ?: "Unknown error")
                }
            } finally {
                urlConnection.inputStream.close()
                urlConnection.disconnect()
                mainHandler.post {
                    onFinished()
                }
            }
        } catch (e: Exception) {
            mainHandler.post {
                onFailure.invoke(-1, e.localizedMessage ?: "Unknown error")
                onFinished()
            }
        }
    }

    @Throws(IOException::class)
    private fun httpsURLConnection(toUrl: String,method: String = "POST"): HttpsURLConnection {
        val url = URL(toUrl)
        val urlConnection = url.openConnection() as HttpsURLConnection
        urlConnection.setDoInput(true)
        urlConnection.setDoOutput(true)
        urlConnection.setUseCaches(false)
        urlConnection.setReadTimeout(180000)
        urlConnection.setConnectTimeout(120000)
        urlConnection.setRequestMethod(method)
        urlConnection.setRequestProperty("Charset", "UTF-8")
        urlConnection.setRequestProperty("Connection", "Keep-Alive")
        urlConnection.setRequestProperty("Content-Type", "application/json")
        urlConnection.setRequestProperty("Accept", "*/*")
        urlConnection.setRequestProperty("product", MullaConfigs.MULLA_APPNAME)
        urlConnection.setRequestProperty("appid", MullaConfigs.MULLA_APPNAME)
        urlConnection.setRequestProperty("p", MullaConfigs.MULLA_APPNAME)
        // add ssl trust
//        urlConnection.setSSLSocketFactory(SSLUtil.createSSLSocketFactory())
//        urlConnection.setHostnameVerifier(SSLUtil.TrustAllHostnameVerifier())
        return urlConnection
    }
}